/*
 * Copyright (c) 2007, Nubo Technologies
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *    * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *    * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
 *    * Neither the name of the Nubo Technologies nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.nubotech.gwt.oss.client.s3;

import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.Hidden;
import com.google.gwt.user.client.ui.Widget;
import com.nubotech.gwt.oss.client.Condition;
import com.nubotech.gwt.oss.client.ui.FileUploadFormPanel;
import com.nubotech.gwt.oss.client.RequestHeader;
import com.nubotech.gwt.oss.client.SecurityPolicy;
import com.nubotech.gwt.oss.client.auth.Credential;
import com.nubotech.gwt.oss.client.util.Base64;
import com.nubotech.gwt.oss.client.util.DateUtils;
import com.nubotech.gwt.oss.client.util.FileUtils;
import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author jonnakkerud
 */
public class S3FileUploadFormPanel extends FileUploadFormPanel {    
    public static final String FILENAME_VAR = "${filename}";
    
    private SecurityPolicy policy;
    private Credential credential;
    private String bucket;
    private boolean useFileName = true;
    
    private Map<String, String> fields = new HashMap<String, String>();
    
    public S3FileUploadFormPanel(Widget innerPanel, Credential credential) {
        this.credential = credential;
        setWidget(innerPanel);
        setEncoding(FormPanel.ENCODING_MULTIPART);
        setMethod(FormPanel.METHOD_POST);
        setField("AWSAccessKeyId", credential.getAccount());
    }
    
    
    public void setBucketName(String name) {
        this.bucket = name;
        String host = getHost();
        if (host == null) {
            host = AwsS3.HOST_URL;
        }
        setAction("https://"+ host + "/" + name);
    }

    /**
     * Set the AccessPolicy for the object
     * @param accessPolicy the access policy
     */
    public void setAccessPolicy(int accessPolicy) {
        setField("acl", AwsS3.accessPolicyString(accessPolicy));
    }
    
    public void setRequestHeaders(RequestHeader[] headers) {
        if (headers == null) return;
        for (int i = 0; i < headers.length; i++) {
            setField(headers[i].getHeaderName(), headers[i].getHeaderValue());
        }
    }
        
    public void setKey(String key) {
        StringBuffer sb = new StringBuffer();
        if (key != null && key.length() > 0) {
            sb.append(key).append("/");
        }
        if (useFileName) {
            sb.append(FILENAME_VAR);
        }
        setField("key", sb.toString());
    }
    
    public void setPolicy(SecurityPolicy policy) {
        this.policy = policy;
    }
    
    public SecurityPolicy getPolicy() {
        if (policy == SecurityPolicy.AUTO) {
            policy.clear();
            policy.setExpiration(DateUtils.today());
            policy.addCondition(Condition.createCondition("bucket", bucket));
            // create
            for (String key : fields.keySet()) {
                if (!"AWSAccessKeyId".equals(key)) {
                    policy.addCondition(Condition.createCondition(key, fields.get(key)));
                }
            }

        }
        return policy;
    }
    
    public void setSuccessActionRedirectUrl(String url) {
        setField("success_action_redirect", url);
    }
    
    public void setSuccessActionStatus(String status) {
        setField("success_action_status", status);
    }
    
    public void setField(String name, String value) {
        fields.put(name, value);
    }
    
    public String getField(String name) {
        return fields.get(name);
    }
    
    public void setContentTypeFromFile(String fileName) {
        setField("Content-Type", getType(fileName));
    }
    
    
    public void setWidget(Widget w) {
        // wrap the widget. All hidden fields must be placed at the top
        super.setWidget(new WidgetWrapper(w));
    }
    
    public Widget getWidget() {
        // return the wrapper
        WidgetWrapper wrapper = (WidgetWrapper)super.getWidget();
        return wrapper.getWidget();
    }

    private String getType(String fileName) {
        return FileUtils.getContentType(fileName);
    }
        
    
    @Override
    public void submit() {
        setDefaults();

        // add signiture
        String policyStr = "";
        SecurityPolicy pol = null;
        if ((pol = getPolicy()) != null) {
            policyStr = Base64.encode(pol.json()).replaceAll("\n","");
            setField("policy", policyStr);
        }
        
        setField("signature", AwsS3.hmacSHA1(policyStr, credential.getSecretKey()));
                
        WidgetWrapper wrapper = (WidgetWrapper)super.getWidget();
        // set the fields
        for (String key : fields.keySet()) {
            //setField(key, fields.get(key));
            wrapper.addField(key, fields.get(key));
        }
        
        fields.clear();
        
        // submit button with name = 'Upload' must be last after 'file'        
        super.submit();
    }

    public boolean isUseFileName() {
        return useFileName;
    }

    public void setUseFileName(boolean useFileName) {
        this.useFileName = useFileName;
    }
    
    private void setDefaults() {
        if (getField("key") == null) {
            setKey("");
            
        }
    }
    
    class WidgetWrapper extends ComplexPanel {
        private Widget wrapped;
        
        public WidgetWrapper(Widget wrappedWidget) {
            setElement(DOM.createDiv());
            setWidget(wrappedWidget);
        }
        
        public void setWidget(Widget w) {
            super.add(w, getElement());
            this.wrapped = w;
        }
        
        public Widget getWidget() {
            return wrapped;
        }
        
        public void addField(String name, String value) {
            super.insert(new Hidden(name, value), getElement(), 0, true);
        }
        
        public void addSubmitButton() {
            //super.add(new SubmitButton(), getElement());
        }
    }     
}
